package com.elasticsearch.service.impl;

import com.elasticsearch.model.Project;
import com.elasticsearch.repository.ProjectRepository;
import com.elasticsearch.service.ProjectService;
import com.google.common.collect.Lists;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.InternalAggregations;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author chong
 * @create 2020/3/24
 * Desc:
 */
@Service
public class ProjectServiceImpl implements ProjectService {


    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private ProjectRepository projectRepository;


    @Autowired
    ElasticsearchTemplate elasticsearchTemplate;


    @Override
    public List<Project> findAllByProCode(String proCode) {
        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        builder.must(QueryBuilders.matchPhraseQuery("proCode",proCode));
        Iterable<Project> search = projectRepository.search(builder);
        return Lists.newArrayList(search);
    }

    @Override
    public Project save(Project project) {
        if(!elasticsearchTemplate.indexExists("project")){
            elasticsearchTemplate.createIndex("project");
            elasticsearchTemplate.createIndex(Project.class);
        }
        // elasticsearchTemplate写法
        IndexQuery indexQuery2 = new IndexQueryBuilder().withId(String.valueOf(project.getId())).withObject(project).build();
//        elasticsearchTemplate.index(indexQuery2);  //单个
//        elasticsearchTemplate.bulkIndex(indexQuery2); //批量
        return projectRepository.save(project);
    }

    @Override
    public List<Project> findAll() {
        String sql = "select * from project";
        List<Project> list = jdbcTemplate.query(sql, new RowMapper<Project>() {
            @Override
            public Project mapRow(ResultSet rs, int rowNum) throws SQLException {
                Project project = new Project();
                project.setId(rs.getLong("id"));
                project.setProCode(rs.getString("proCode"));
                project.setProName(rs.getString("proName"));
                project.setAddDateTime(rs.getDate("addDateTime"));
                project.setIfCentralizedStorage(rs.getInt("ifCentralizedStorage"));
                project.setIfMgtStorage(rs.getInt("ifMgtStorage"));
                project.setIfFundsReply(rs.getInt("ifFundsReply"));
                project.setIfDelete(rs.getInt("ifDelete"));
                project.setUseMark(rs.getInt("useMark"));
                project.setGeneralOpinion(rs.getString("generalOpinion"));
                project.setProgressNum(rs.getInt("progressNum"));
                return project;
            }
        });
        return list;
    }

    @Override
    public void savaAll(List<Project> list) {
        projectRepository.saveAll(list);
    }

    @Override
    public Page<Project> queryProPageList(Pageable pageable) {
        pageable = PageRequest.of(0,10, Sort.Direction.ASC,"id");
        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        builder.must(QueryBuilders.matchPhraseQuery("proCode", "SKD202003090001"));
        // 高亮
        HighlightBuilder.Field hfieldName = new HighlightBuilder.Field("name")
                .preTags("<em style='color:red'>")
                .postTags("</em>")
                .fragmentSize(100);
        HighlightBuilder.Field hfieldAns = new HighlightBuilder.Field("answer")
                .preTags("<em style='color:red'>")
                .postTags("</em>")
                .fragmentSize(100);
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(builder)
                .withPageable(pageable)
                .withHighlightFields(hfieldName,hfieldAns)
                .build();
        //Page<Project> search = projectRepository.search(builder, pageable);
        Page<Project> page = elasticsearchTemplate.queryForPage(searchQuery, Project.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                List<T> chunk = new ArrayList<T>();
                for (SearchHit searchHit : response.getHits().getHits()) {
                    Map<String, Object> smap = searchHit.getSourceAsMap();
                    Map<String, HighlightField> hmap = searchHit.getHighlightFields();
                    chunk.add((T)createEsDoc(smap,hmap));
                }
                AggregatedPage<T> result=new AggregatedPageImpl<T>(chunk,pageable,response.getHits().getTotalHits());
                return result;
            }

            @Override
            public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
                return null;
            }
        });


        //  elasticsearchTemplate写法
       /* Pageable pageable= new PageRequest(0, 20,new Sort(Sort.Direction.DESC, "name"));
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.queryStringQuery("菜鸟"))
                .withPageable(pageable)
                .build();
        Page<Project> list = elasticsearchTemplate.queryForPage(searchQuery, Project.class);*/
        return page;
    }
    /**
     * 返回结果高亮显示
     * @param smap
     * @param hmap
     * @return
     */
    private Project createEsDoc(Map<String, Object> smap,Map<String, HighlightField> hmap){
        Project ed = new Project();
        if (hmap.get("proName") != null){
            ed.setProName(hmap.get("proName").fragments()[0].toString());
        }else {
            ed.setProName(smap.get("proName").toString());
        }
       /* if (hmap.get("answer") != null)
            ed.setAnswer(hmap.get("answer").fragments()[0].toString());*/
        if (smap.get("id") != null)
            ed.setId(Long.parseLong(smap.get("id").toString()));
        return ed;
    }

    /**
     * 分页返回数据json 序列化转换报错处理
     *
     * @param page
     * @param <T>
     * @return
     */
    private <T> Page<T> fixEmptyPage(Page<T> page) {
        AggregatedPageImpl<T> aggregatedPage = (AggregatedPageImpl<T>) page;
        Aggregations aggregations = aggregatedPage.getAggregations();
        if (aggregations == null) {
            Field field = ReflectionUtils.findField(AggregatedPageImpl.class, "aggregations");
            ReflectionUtils.makeAccessible(field);
            ReflectionUtils.setField(field, aggregatedPage, InternalAggregations.EMPTY);
            return aggregatedPage;
        }
        return page;
    }
}
